home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_ka9q / ftpsrv.z / ftpsrv
Text File  |  1996-06-25  |  26KB  |  1,302 lines

  1. head    1.13;
  2. access;
  3. symbols;
  4. locks;
  5. comment    @ * @;
  6.  
  7.  
  8. 1.13
  9. date    93.01.21.06.19.03;    author ssampson;    state Exp;
  10. branches;
  11. next    1.12;
  12.  
  13. 1.12
  14. date    92.12.28.09.01.43;    author karn;    state Exp;
  15. branches;
  16. next    1.11;
  17.  
  18. 1.11
  19. date    92.12.21.21.25.54;    author karn;    state Exp;
  20. branches;
  21. next    1.10;
  22.  
  23. 1.10
  24. date    92.12.17.20.48.07;    author karn;    state Exp;
  25. branches;
  26. next    1.9;
  27.  
  28. 1.9
  29. date    92.09.07.21.05.39;    author karn;    state Exp;
  30. branches;
  31. next    1.8;
  32.  
  33. 1.8
  34. date    92.06.03.22.02.42;    author karn;    state Exp;
  35. branches;
  36. next    1.7;
  37.  
  38. 1.7
  39. date    92.05.29.23.28.14;    author karn;    state Exp;
  40. branches;
  41. next    1.6;
  42.  
  43. 1.6
  44. date    92.05.19.22.14.12;    author karn;    state Exp;
  45. branches;
  46. next    1.5;
  47.  
  48. 1.5
  49. date    92.05.19.06.32.12;    author karn;    state Exp;
  50. branches;
  51. next    1.4;
  52.  
  53. 1.4
  54. date    92.05.03.11.01.42;    author karn;    state Exp;
  55. branches;
  56. next    1.3;
  57.  
  58. 1.3
  59. date    92.05.01.11.46.36;    author karn;    state Exp;
  60. branches;
  61. next    1.2;
  62.  
  63. 1.2
  64. date    91.03.16.15.35.04;    author karn;    state Exp;
  65. branches;
  66. next    1.1;
  67.  
  68. 1.1
  69. date    91.01.27.11.50.36;    author karn;    state Exp;
  70. branches;
  71. next    ;
  72.  
  73.  
  74. desc
  75. @src0201
  76. @
  77.  
  78.  
  79. 1.13
  80. log
  81. @changed access() to stat()
  82. @
  83. text
  84. @/* Internet FTP Server
  85.  * Copyright 1991 Phil Karn, KA9Q
  86.  */
  87. #include <stdio.h>
  88. #include <ctype.h>
  89. #include <time.h>
  90. #include <sys/stat.h>
  91. #ifdef    __TURBOC__
  92. #include <io.h>
  93. #include <dir.h>
  94. #endif
  95. #include "global.h"
  96. #include "mbuf.h"
  97. #include "proc.h"
  98. #include "socket.h"
  99. #include "dirutil.h"
  100. #include "commands.h"
  101. #include "files.h"
  102. #include "ftp.h"
  103. #include "ftpserv.h"
  104. #include "md5.h"
  105.  
  106. static void ftpserv __ARGS((int s,void *unused,void *p));
  107. static int pport __ARGS((struct sockaddr_in *sock,char *arg));
  108. static void ftplogin __ARGS((struct ftpserv *ftp,char *pass));
  109. static int sendit __ARGS((struct ftpserv *ftp,char *command,char *file));
  110. static int recvit __ARGS((struct ftpserv *ftp,char *command,char *file));
  111.  
  112. /* Command table */
  113. static char *commands[] = {
  114.     "user",
  115.     "acct",
  116.     "pass",
  117.     "type",
  118.     "list",
  119.     "cwd",
  120.     "dele",
  121.     "name",
  122.     "quit",
  123.     "retr",
  124.     "stor",
  125.     "port",
  126.     "nlst",
  127.     "pwd",
  128.     "xpwd",            /* For compatibility with 4.2BSD */
  129.     "mkd ",
  130.     "xmkd",            /* For compatibility with 4.2BSD */
  131.     "xrmd",            /* For compatibility with 4.2BSD */
  132.     "rmd ",
  133.     "stru",
  134.     "mode",
  135.     "syst",
  136.     "xmd5",
  137.     NULLCHAR
  138. };
  139.  
  140. /* Response messages */
  141. static char banner[] = "220 %s FTP version %s ready at %s\n";
  142. static char badcmd[] = "500 Unknown command '%s'\n";
  143. static char binwarn[] = "100 Warning: type is ASCII and %s appears to be binary\n";
  144. static char unsupp[] = "500 Unsupported command or option\n";
  145. static char givepass[] = "331 Enter PASS command\n";
  146. static char logged[] = "230 Logged in\n";
  147. static char typeok[] = "200 Type %s OK\n";
  148. static char only8[] = "501 Only logical bytesize 8 supported\n";
  149. static char deleok[] = "250 File deleted\n";
  150. static char mkdok[] = "200 MKD ok\n";
  151. static char delefail[] = "550 Delete failed: %s\n";
  152. static char pwdmsg[] = "257 \"%s\" is current directory\n";
  153. static char badtype[] = "501 Unknown type \"%s\"\n";
  154. static char badport[] = "501 Bad port syntax\n";
  155. static char unimp[] = "502 Command not yet implemented\n";
  156. static char bye[] = "221 Goodbye!\n";
  157. static char nodir[] = "553 Can't read directory \"%s\": %s\n";
  158. static char cantopen[] = "550 Can't read file \"%s\": %s\n";
  159. static char sending[] = "150 Opening data connection for %s %s\n";
  160. static char cantmake[] = "553 Can't create \"%s\": %s\n";
  161. static char writerr[] = "552 Write error: %s\n";
  162. static char portok[] = "200 Port command okay\n";
  163. static char rxok[] = "226 File received OK\n";
  164. static char txok[] = "226 File sent OK\n";
  165. static char noperm[] = "550 Permission denied\n";
  166. static char noconn[] = "425 Data connection reset\n";
  167. static char lowmem[] = "421 System overloaded, try again later\n";
  168. static char notlog[] = "530 Please log in with USER and PASS\n";
  169. static char userfirst[] = "503 Login with USER first.\n";
  170. static char okay[] = "200 Ok\n";
  171. static char syst[] = "215 %s Type: L%d Version: %s\n";
  172.  
  173. static int Sftp = -1;    /* Prototype socket for service */
  174.  
  175. /* Start up FTP service */
  176. int
  177. ftpstart(argc,argv,p)
  178. int argc;
  179. char *argv[];
  180. void *p;
  181. {
  182.     struct sockaddr_in lsocket;
  183.     int s;
  184.     FILE *network;
  185.  
  186.     if(Sftp != -1){
  187.         /* Already running! */
  188.         return 0;
  189.     }
  190.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  191.     chname(Curproc,"FTP listener");
  192.  
  193.     lsocket.sin_family = AF_INET;
  194.     lsocket.sin_addr.s_addr = INADDR_ANY;
  195.     if(argc < 2)
  196.         lsocket.sin_port = IPPORT_FTP;
  197.     else
  198.         lsocket.sin_port = atoi(argv[1]);
  199.  
  200.     Sftp = socket(AF_INET,SOCK_STREAM,0);
  201.     bind(Sftp,(char *)&lsocket,sizeof(lsocket));
  202.     listen(Sftp,1);
  203.     for(;;){
  204.         if((s = accept(Sftp,NULLCHAR,(int *)NULL)) == -1)
  205.             break;    /* Service is shutting down */
  206.  
  207.         network = fdopen(s,"r+t");
  208.         if(availmem() != 0){
  209.             fprintf(network,lowmem);
  210.             fclose(network);
  211.         } else {
  212.             /* Spawn a server */
  213.             newproc("ftpserv",2048,ftpserv,s,(void *)network,NULL,0);
  214.         }
  215.     }
  216.     return 0;
  217. }
  218. static void
  219. ftpserv(s,n,p)
  220. int s;    /* Socket with user connection */
  221. void *n;
  222. void *p;
  223. {
  224.     struct ftpserv ftp;
  225.     char **cmdp,buf[512],*arg,*cp,*cp1,*file,*mode;
  226.     long t;
  227.     int i;
  228.     struct sockaddr_in socket;
  229.  
  230.     memset((char *)&ftp,0,sizeof(ftp));    /* Start with clear slate */
  231.     ftp.control = (FILE *)n;
  232.     fclose(stdin);
  233.     stdin = fdup(ftp.control);
  234.     fclose(stdout);
  235.     stdout = fdup(ftp.control);
  236.  
  237.     sockowner(fileno(ftp.control),Curproc);        /* We own it now */
  238.     /* Set default data port */
  239.     i = SOCKSIZE;
  240.     getpeername(fileno(ftp.control),(char *)&socket,&i);
  241.     socket.sin_port = IPPORT_FTPD;
  242.     ASSIGN(ftp.port,socket);
  243.  
  244.     log(fileno(ftp.control),"open FTP");
  245.     time(&t);
  246.     cp = ctime(&t);
  247.     if((cp1 = strchr(cp,'\n')) != NULLCHAR)
  248.         *cp1 = '\0';
  249.     fprintf(ftp.control,banner,Hostname,Version,cp);
  250. loop:    fflush(ftp.control);
  251.     if((fgets(buf,sizeof(buf),ftp.control)) == NULLCHAR){
  252.         /* He closed on us */
  253.         goto finish;
  254.     }
  255.     if(strlen(buf) == 0){
  256.         /* Can't be a legal FTP command */
  257.         fprintf(ftp.control,badcmd,buf);
  258.         goto loop;
  259.     }    
  260.     rip(buf);
  261. #ifdef    UNIX
  262.     /* Translate first word to lower case */
  263.     for(cp = buf;*cp != ' ' && *cp != '\0';cp++)
  264.         *cp = tolower(*cp);
  265. #else
  266.     /* Translate entire buffer to lower case */
  267.     for(cp = buf;*cp != '\0';cp++)
  268.         *cp = tolower(*cp);
  269. #endif
  270.     /* Find command in table; if not present, return syntax error */
  271.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  272.         if(strncmp(*cmdp,buf,strlen(*cmdp)) == 0)
  273.             break;
  274.     if(*cmdp == NULLCHAR){
  275.         fprintf(ftp.control,badcmd,buf);
  276.         goto loop;
  277.     }
  278.     /* Allow only USER, PASS and QUIT before logging in */
  279.     if(ftp.cd == NULLCHAR || ftp.path == NULLCHAR){
  280.         switch(cmdp-commands){
  281.         case USER_CMD:
  282.         case PASS_CMD:
  283.         case QUIT_CMD:
  284.             break;
  285.         default:
  286.             fprintf(ftp.control,notlog);
  287.             goto loop;
  288.         }
  289.     }
  290.     arg = &buf[strlen(*cmdp)];
  291.     while(*arg == ' ')
  292.         arg++;
  293.  
  294.     /* Execute specific command */
  295.     switch(cmdp-commands){
  296.     case USER_CMD:
  297.         free(ftp.username);
  298.         ftp.username = strdup(arg);
  299.         fprintf(ftp.control,givepass);
  300.         break;
  301.     case TYPE_CMD:
  302.         switch(arg[0]){
  303.         case 'A':
  304.         case 'a':    /* Ascii */
  305.             ftp.type = ASCII_TYPE;
  306.             fprintf(ftp.control,typeok,arg);
  307.             break;
  308.         case 'l':
  309.         case 'L':
  310.             while(*arg != ' ' && *arg != '\0')
  311.                 arg++;
  312.             if(*arg == '\0' || *++arg != '8'){
  313.                 fprintf(ftp.control,only8);
  314.                 break;
  315.             }
  316.             ftp.type = LOGICAL_TYPE;
  317.             ftp.logbsize = 8;
  318.             fprintf(ftp.control,typeok,arg);
  319.             break;
  320.         case 'B':
  321.         case 'b':    /* Binary */
  322.         case 'I':
  323.         case 'i':    /* Image */
  324.             ftp.type = IMAGE_TYPE;
  325.             fprintf(ftp.control,typeok,arg);
  326.             break;
  327.         default:    /* Invalid */
  328.             fprintf(ftp.control,badtype,arg);
  329.             break;
  330.         }
  331.         break;
  332.     case QUIT_CMD:
  333.         fprintf(ftp.control,bye);
  334.         goto finish;
  335.     case RETR_CMD:
  336.         file = pathname(ftp.cd,arg);
  337.         switch(ftp.type){
  338.         case IMAGE_TYPE:
  339.         case LOGICAL_TYPE:
  340.             mode = READ_BINARY;
  341.             break;
  342.         case ASCII_TYPE:
  343.             mode = READ_TEXT;
  344.             break;
  345.         }
  346.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  347.              fprintf(ftp.control,noperm);
  348.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  349.             fprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  350.         } else {
  351.             log(fileno(ftp.control),"RETR %s",file);
  352.             if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
  353.                 fprintf(ftp.control,binwarn,file);
  354.             }
  355.             sendit(&ftp,"RETR",file);
  356.         }
  357.         free(file);
  358.         break;
  359.     case STOR_CMD:
  360.         file = pathname(ftp.cd,arg);
  361.         switch(ftp.type){
  362.         case IMAGE_TYPE:
  363.         case LOGICAL_TYPE:
  364.             mode = WRITE_BINARY;
  365.             break;
  366.         case ASCII_TYPE:
  367.             mode = WRITE_TEXT;
  368.             break;
  369.         }
  370.         if(!permcheck(ftp.path,ftp.perms,STOR_CMD,file)){
  371.              fprintf(ftp.control,noperm);
  372.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  373.             fprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  374.         } else {
  375.             log(fileno(ftp.control),"STOR %s",file);
  376.             recvit(&ftp,"STOR",file);
  377.         }
  378.         free(file);
  379.         break;
  380.     case PORT_CMD:
  381.         if(pport(&ftp.port,arg) == -1){
  382.             fprintf(ftp.control,badport);
  383.         } else {
  384.             fprintf(ftp.control,portok);
  385.         }
  386.         break;
  387. #ifndef CPM
  388.     case LIST_CMD:
  389.         file = pathname(ftp.cd,arg);
  390.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  391.              fprintf(ftp.control,noperm);
  392.         } else if((ftp.fp = dir(file,1)) == NULLFILE){
  393.             fprintf(ftp.control,nodir,file,sys_errlist[errno]);
  394.         } else {
  395.             sendit(&ftp,"LIST",file);
  396.         }
  397.         free(file);
  398.         break;
  399.     case NLST_CMD:
  400.         file = pathname(ftp.cd,arg);
  401.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  402.              fprintf(ftp.control,noperm);
  403.         } else if((ftp.fp = dir(file,0)) == NULLFILE){
  404.             fprintf(ftp.control,nodir,file,sys_errlist[errno]);
  405.         } else {
  406.             sendit(&ftp,"NLST",file);
  407.         }
  408.         free(file);
  409.         break;
  410.     case CWD_CMD:
  411.         file = pathname(ftp.cd,arg);
  412.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  413.              fprintf(ftp.control,noperm);
  414.             free(file);
  415. #ifdef MSDOS
  416.         } else if ((strcmp(file,"/") == 0) ||
  417.             ((stat(file, &cwdstat) == 0) &&
  418.                 (cwdstat.st_mode & S_IFDIR)))  {
  419. #else
  420.         } else if (stat(file, &cwdstat) == 0 &&
  421.             (cwdstat.st_mode & S_IFDIR)) {    /* See if it exists */
  422. #endif
  423.             /* Succeeded, record in control block */
  424.             free(ftp.cd);
  425.             ftp.cd = file;
  426.             fprintf(ftp.control,pwdmsg,file);
  427.         } else {
  428.             /* Failed, don't change anything */
  429.             fprintf(ftp.control,nodir,file,sys_errlist[errno]);
  430.             free(file);
  431.         }
  432.         break;
  433.     case XPWD_CMD:
  434.     case PWD_CMD:
  435.         fprintf(ftp.control,pwdmsg,ftp.cd);
  436.         break;
  437. #else
  438.     case LIST_CMD:
  439.     case NLST_CMD:
  440.     case CWD_CMD:
  441.     case XPWD_CMD:
  442.     case PWD_CMD:
  443. #endif
  444.     case ACCT_CMD:        
  445.         fprintf(ftp.control,unimp);
  446.         break;
  447.     case DELE_CMD:
  448.         file = pathname(ftp.cd,arg);
  449.         if(!permcheck(ftp.path,ftp.perms,DELE_CMD,file)){
  450.              fprintf(ftp.control,noperm);
  451.         } else if(unlink(file) == 0){
  452.             log(fileno(ftp.control),"DELE %s",file);
  453.             fprintf(ftp.control,deleok);
  454.         } else {
  455.             fprintf(ftp.control,delefail,sys_errlist[errno]);
  456.         }
  457.         free(file);
  458.         break;
  459.     case PASS_CMD:
  460.         if(ftp.username == NULLCHAR)
  461.             fprintf(ftp.control,userfirst);
  462.         else
  463.             ftplogin(&ftp,arg);            
  464.         break;
  465. #ifndef    CPM
  466.     case XMKD_CMD:
  467.     case MKD_CMD:
  468.         file = pathname(ftp.cd,arg);
  469.         if(!permcheck(ftp.path,ftp.perms,MKD_CMD,file)){
  470.             fprintf(ftp.control,noperm);
  471. #ifdef    UNIX
  472.         } else if(mkdir(file,0777) == 0){
  473. #else
  474.         } else if(mkdir(file) == 0){
  475. #endif
  476.             log(fileno(ftp.control),"MKD %s",file);
  477.             fprintf(ftp.control,mkdok);
  478.         } else {
  479.             fprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  480.         }
  481.         free(file);
  482.         break;
  483.     case XRMD_CMD:
  484.     case RMD_CMD:
  485.         file = pathname(ftp.cd,arg);
  486.         if(!permcheck(ftp.path,ftp.perms,RMD_CMD,file)){
  487.              fprintf(ftp.control,noperm);
  488.         } else if(rmdir(file) == 0){
  489.             log(fileno(ftp.control),"RMD %s",file);
  490.             fprintf(ftp.control,deleok);
  491.         } else {
  492.             fprintf(ftp.control,delefail,sys_errlist[errno]);
  493.         }
  494.         free(file);
  495.         break;
  496.     case STRU_CMD:
  497.         if(tolower(arg[0]) != 'f')
  498.             fprintf(ftp.control,unsupp);
  499.         else
  500.             fprintf(ftp.control,okay);
  501.         break;
  502.     case MODE_CMD:
  503.         if(tolower(arg[0]) != 's')
  504.             fprintf(ftp.control,unsupp);
  505.         else
  506.             fprintf(ftp.control,okay);
  507.         break;
  508.     case SYST_CMD:
  509.         fprintf(ftp.control,syst,System,NBBY,Version);
  510.         break;
  511.     case XMD5_CMD:
  512.         file = pathname(ftp.cd,arg);
  513.         switch(ftp.type){
  514.         case IMAGE_TYPE:
  515.         case LOGICAL_TYPE:
  516.             mode = READ_BINARY;
  517.             break;
  518.         case ASCII_TYPE:
  519.             mode = READ_TEXT;
  520.             break;
  521.         }
  522.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  523.              fprintf(ftp.control,noperm);
  524.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  525.             fprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  526.         } else {
  527.             char hash[16];
  528.  
  529.             log(fileno(ftp.control),"XMD5 %s",file);
  530.             if(ftp.type == ASCII_TYPE && isbinary(ftp.fp))
  531.                 fprintf(ftp.control,binwarn,file);
  532.  
  533.             md5hash(ftp.fp,hash,ftp.type == ASCII_TYPE);
  534.             fclose(ftp.fp);
  535.             ftp.fp = NULLFILE;
  536.             fprintf(ftp.control,"200 ");
  537.             for(i=0;i<16;i++)
  538.                 fprintf(ftp.control,"%02x",hash[i] & 0xff);
  539.             fprintf(ftp.control," %s\n",file);
  540.         }
  541.         free(file);
  542.         break;
  543.     }
  544. #endif
  545.     goto loop;
  546. finish:
  547.     log(fileno(ftp.control),"close FTP");
  548.     /* Clean up */
  549.     fclose(ftp.control);
  550.     if(ftp.data != NULLFILE)
  551.         fclose(ftp.data);
  552.     if(ftp.fp != NULLFILE)
  553.         fclose(ftp.fp);
  554.     free(ftp.username);
  555.     free(ftp.path);
  556.     free(ftp.cd);
  557. }
  558.  
  559. /* Shut down FTP server */
  560. int
  561. ftp0(argc,argv,p)
  562. int argc;
  563. char *argv[];
  564. void *p;
  565. {
  566.     close_s(Sftp);
  567.     Sftp = -1;
  568.     return 0;
  569. }
  570. static
  571. int
  572. pport(sock,arg)
  573. struct sockaddr_in *sock;
  574. char *arg;
  575. {
  576.     int32 n;
  577.     int i;
  578.  
  579.     n = 0;
  580.     for(i=0;i<4;i++){
  581.         n = atoi(arg) + (n << 8);
  582.         if((arg = strchr(arg,',')) == NULLCHAR)
  583.             return -1;
  584.         arg++;
  585.     }
  586.     sock->sin_addr.s_addr = n;
  587.     n = atoi(arg);
  588.     if((arg = strchr(arg,',')) == NULLCHAR)
  589.         return -1;
  590.     arg++;
  591.     n = atoi(arg) + (n << 8);
  592.     sock->sin_port = n;
  593.     return 0;
  594. }
  595.  
  596. /* Attempt to log in the user whose name is in ftp->username and password
  597.  * in pass
  598.  */
  599. static void
  600. ftplogin(ftp,pass)
  601. struct ftpserv *ftp;
  602. char *pass;
  603. {
  604.     char *path;
  605.     int anony = 0;
  606.  
  607.     path = mallocw(200);
  608.     if((ftp->perms = userlogin(ftp->username,pass,&path,200,&anony))
  609.        == -1){
  610.         fprintf(ftp->control,noperm);
  611.         free(path);
  612.         return;
  613.     }
  614.     /* Set up current directory and path prefix */
  615. #if    defined(AMIGAGONE)
  616.     ftp->cd = pathname("", path);
  617.     ftp->path = strdup(ftp->cd);
  618.     free(path);
  619. #else
  620.     ftp->cd = path;
  621.     ftp->path = strdup(path);
  622. #endif
  623.  
  624.     fprintf(ftp->control,logged);
  625.     if(!anony)
  626.         log(fileno(ftp->control),"%s logged in",ftp->username);
  627.     else
  628.         log(fileno(ftp->control),"%s logged in, ID %s",ftp->username,pass);
  629. }
  630.  
  631. #ifdef    MSDOS
  632. /* Illegal characters in a DOS filename */
  633. static char badchars[] = "\"[]:|<>+=;,";
  634. #endif
  635.  
  636. /* Return 1 if the file operation is allowed, 0 otherwise */
  637. int
  638. permcheck(path,perms,op,file)
  639. char *path;
  640. int perms;
  641. int op;
  642. char *file;
  643. {
  644. #ifdef    MSDOS
  645.     char *cp;
  646. #endif
  647.  
  648.     if(file == NULLCHAR || path == NULLCHAR)
  649.         return 0;    /* Probably hasn't logged in yet */
  650. #ifdef    MSDOS
  651.     /* Check for characters illegal in MS-DOS file names */
  652.     for(cp = badchars;*cp != '\0';cp++){
  653.         if(strchr(file,*cp) != NULLCHAR)
  654.             return 0;    
  655.     }
  656. #endif
  657. #ifndef MAC
  658.     /* The target file must be under the user's allowed search path */
  659.     if(strncmp(file,path,strlen(path)) != 0)
  660.         return 0;
  661. #endif
  662.  
  663.     switch(op){
  664.     case RETR_CMD:
  665.         /* User must have permission to read files */
  666.         if(perms & FTP_READ)
  667.             return 1;
  668.         return 0;
  669.     case DELE_CMD:
  670.     case RMD_CMD:
  671.         /* User must have permission to (over)write files */
  672.         if(perms & FTP_WRITE)
  673.             return 1;
  674.         return 0;
  675.     case STOR_CMD:
  676.     case MKD_CMD:
  677.         /* User must have permission to (over)write files, or permission
  678.          * to create them if the file doesn't already exist
  679.          */
  680.         if(perms & FTP_WRITE)
  681.             return 1;
  682.         if(access(file,2) == -1 && (perms & FTP_CREATE))
  683.             return 1;
  684.         return 0;
  685.     }
  686.     return 0;    /* "can't happen" -- keep lint happy */
  687. }
  688. static int
  689. sendit(ftp,command,file)
  690. struct ftpserv *ftp;
  691. char *command;
  692. char *file;
  693. {
  694.     long total;
  695.     struct sockaddr_in dport;
  696.     int s;
  697.  
  698.     s = socket(AF_INET,SOCK_STREAM,0);
  699.     dport.sin_family = AF_INET;
  700.     dport.sin_addr.s_addr = INADDR_ANY;
  701.     dport.sin_port = IPPORT_FTPD;
  702.     bind(s,(char *)&dport,SOCKSIZE);
  703.     fprintf(ftp->control,sending,command,file);
  704.     fflush(ftp->control);
  705.     if(connect(s,(char *)&ftp->port,SOCKSIZE) == -1){
  706.         fclose(ftp->fp);
  707.         ftp->fp = NULLFILE;
  708.         close_s(s);
  709.         ftp->data = NULLFILE;
  710.         fprintf(ftp->control,noconn);
  711.         return -1;
  712.     }
  713.     ftp->data = fdopen(s,"r+");
  714.     /* Do the actual transfer */
  715.     total = sendfile(ftp->fp,ftp->data,ftp->type,0);
  716.  
  717.     if(total == -1){
  718.         /* An error occurred on the data connection */
  719.         fprintf(ftp->control,noconn);
  720.         shutdown(fileno(ftp->data),2);    /* Blow away data connection */
  721.         fclose(ftp->data);
  722.     } else {
  723.         fprintf(ftp->control,txok);
  724.     }
  725.     fclose(ftp->fp);
  726.     ftp->fp = NULLFILE;
  727.     fclose(ftp->data);
  728.     ftp->data = NULLFILE;
  729.     if(total == -1)
  730.         return -1;
  731.     else
  732.         return 0;
  733. }
  734. static int
  735. recvit(ftp,command,file)
  736. struct ftpserv *ftp;
  737. char *command;
  738. char *file;
  739. {
  740.     struct sockaddr_in dport;
  741.     long total;
  742.     int s;
  743.  
  744.     s = socket(AF_INET,SOCK_STREAM,0);
  745.     dport.sin_family = AF_INET;
  746.     dport.sin_addr.s_addr = INADDR_ANY;
  747.     dport.sin_port = IPPORT_FTPD;
  748.     bind(s,(char *)&dport,SOCKSIZE);
  749.     fprintf(ftp->control,sending,command,file);
  750.     fflush(ftp->control);
  751.     if(connect(s,(char *)&ftp->port,SOCKSIZE) == -1){
  752.         fclose(ftp->fp);
  753.         ftp->fp = NULLFILE;
  754.         close_s(s);
  755.         ftp->data = NULLCHAR;
  756.         fprintf(ftp->control,noconn);
  757.         return -1;
  758.     }
  759.     ftp->data = fdopen(s,"r+");
  760.     /* Do the actual transfer */
  761.     total = recvfile(ftp->fp,ftp->data,ftp->type,0);
  762.  
  763. #ifdef    CPM
  764.     if(ftp->type == ASCII_TYPE)
  765.         putc(CTLZ,ftp->fp);
  766. #endif
  767.     if(total == -1) {
  768.         /* An error occurred while writing the file */
  769.         fprintf(ftp->control,writerr,sys_errlist[errno]);
  770.         shutdown(fileno(ftp->data),2);    /* Blow it away */
  771.         fclose(ftp->data);
  772.     } else {
  773.         fprintf(ftp->control,rxok);
  774.         fclose(ftp->data);
  775.     }
  776.     ftp->data = NULLFILE;
  777.     fclose(ftp->fp);
  778.     ftp->fp = NULLFILE;
  779.     if(total == -1)
  780.         return -1;
  781.     else
  782.         return 0;
  783. }
  784. @
  785.  
  786.  
  787. 1.12
  788. log
  789. @Pass ascii flag to md5hash()
  790. @
  791. text
  792. @d7 1
  793. d332 4
  794. a335 3
  795. #ifdef    MSDOS
  796.         /* Don'tcha just LOVE %%$#@@!! MS-DOS? */
  797.         } else if(strcmp(file,"/") == 0 || access(file,0) == 0){
  798. d337 2
  799. a338 1
  800.         } else if(access(file,0) == 0){    /* See if it exists */
  801. @
  802.  
  803.  
  804. 1.11
  805. log
  806. @Move md5 file hashing into common subroutine
  807. @
  808. text
  809. @d447 1
  810. a447 1
  811.             md5hash(ftp.fp,hash);
  812. @
  813.  
  814.  
  815. 1.10
  816. log
  817. @Add XMD5 command to produce MD5 hash of a file. Should be extended
  818. to handle a seek offset and length. Also need to think about ascii
  819. file standards (netascii?)
  820. @
  821. text
  822. @d441 1
  823. a441 3
  824.             MD5_CTX md;
  825.             char *buf;
  826.             int len;
  827. d444 1
  828. a444 1
  829.             if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
  830. d446 2
  831. a447 8
  832.             }
  833.             MD5Init(&md);
  834.             buf = malloc(BUFSIZ);
  835.             while((len = fread(buf,1,BUFSIZ,ftp.fp)) != 0){
  836.                 MD5Update(&md,buf,len);
  837.                 pwait(NULL);
  838.             }
  839.             free(buf);
  840. a449 1
  841.             MD5Final(&md);
  842. d452 2
  843. a453 2
  844.                 fprintf(ftp.control,"%02x",md.digest[i]);
  845.             fprintf(ftp.control,"\n");
  846. @
  847.  
  848.  
  849. 1.9
  850. log
  851. @Implement SYST command, also add echoing of bad commands
  852. @
  853. text
  854. @d20 1
  855. d52 1
  856. d424 41
  857. @
  858.  
  859.  
  860. 1.8
  861. log
  862. @s920603
  863. @
  864. text
  865. @d50 1
  866. d56 1
  867. a56 1
  868. static char badcmd[] = "500 Unknown command\n";
  869. d85 1
  870. d171 1
  871. a171 1
  872.         fprintf(ftp.control,badcmd);
  873. d189 1
  874. a189 1
  875.         fprintf(ftp.control,badcmd);
  876. d419 3
  877. @
  878.  
  879.  
  880. 1.7
  881. log
  882. @s920529
  883. @
  884. text
  885. @d144 4
  886. @
  887.  
  888.  
  889. 1.6
  890. log
  891. @src0519
  892. @
  893. text
  894. @d631 1
  895. @
  896.  
  897.  
  898. 1.5
  899. log
  900. @src0518
  901. @
  902. text
  903. @d120 1
  904. a120 1
  905.         if(availmem() < Memthresh){
  906. @
  907.  
  908.  
  909. 1.4
  910. log
  911. @src0503
  912. @
  913. text
  914. @a140 1
  915.     FILE *network;
  916. a141 2
  917.     network = (FILE *)n;
  918.     
  919. d143 1
  920. a143 1
  921.     ftp.data = NULLFILE;
  922. d145 1
  923. a145 2
  924.     sockowner(fileno(network),Curproc);        /* We own it now */
  925.     ftp.control = network;
  926. d148 1
  927. a148 1
  928.     getpeername(fileno(network),(char *)&socket,&i);
  929. d152 1
  930. a152 1
  931.     log(fileno(network),"open FTP");
  932. d157 3
  933. a159 2
  934.     fprintf(network,banner,Hostname,Version,cp);
  935. loop:    if((fgets(buf,sizeof(buf),network)) == NULLCHAR){
  936. d575 1
  937. d621 1
  938. @
  939.  
  940.  
  941. 1.3
  942. log
  943. @src0501
  944. @
  945. text
  946. @d119 1
  947. a119 2
  948.         network = fdopen(s,"r+");
  949.         seteol(network,eolseq(s));
  950. a143 2
  951.     seteol(network,eolseq(fileno(network)));
  952.     fmode(network,STREAM_ASCII);
  953. @
  954.  
  955.  
  956. 1.2
  957. log
  958. @src0318
  959. @
  960. text
  961. @d96 1
  962. d119 2
  963. d122 2
  964. a123 2
  965.             usprintf(s,lowmem);
  966.             shutdown(s,1);
  967. d126 1
  968. a126 1
  969.             newproc("ftpserv",2048,ftpserv,s,NULL,NULL,0);
  970. d132 1
  971. a132 1
  972. ftpserv(s,unused,p)
  973. d134 1
  974. a134 1
  975. void *unused;
  976. d140 1
  977. a140 1
  978.     int cnt,i;
  979. d142 1
  980. d144 4
  981. a147 1
  982.     sockmode(s,SOCK_ASCII);
  983. d149 1
  984. a149 1
  985.     ftp.data = -1;
  986. d151 2
  987. a152 2
  988.     sockowner(s,Curproc);        /* We own it now */
  989.     ftp.control = s;
  990. d155 1
  991. a155 1
  992.     getpeername(s,(char *)&socket,&i);
  993. d159 1
  994. a159 1
  995.     log(s,"open FTP");
  996. d164 2
  997. a165 2
  998.     usprintf(s,banner,Hostname,Version,cp);
  999. loop:    if((cnt = recvline(s,buf,sizeof(buf))) == -1){
  1000. d169 1
  1001. a169 1
  1002.     if(cnt == 0){
  1003. d171 1
  1004. a171 1
  1005.         usprintf(ftp.control,badcmd);
  1006. d189 1
  1007. a189 1
  1008.         usprintf(ftp.control,badcmd);
  1009. d200 1
  1010. a200 1
  1011.             usprintf(ftp.control,notlog);
  1012. d213 1
  1013. a213 1
  1014.         usprintf(ftp.control,givepass);
  1015. d220 1
  1016. a220 1
  1017.             usprintf(ftp.control,typeok,arg);
  1018. d227 1
  1019. a227 1
  1020.                 usprintf(ftp.control,only8);
  1021. d232 1
  1022. a232 1
  1023.             usprintf(ftp.control,typeok,arg);
  1024. d239 1
  1025. a239 1
  1026.             usprintf(ftp.control,typeok,arg);
  1027. d242 1
  1028. a242 1
  1029.             usprintf(ftp.control,badtype,arg);
  1030. d247 1
  1031. a247 1
  1032.         usprintf(ftp.control,bye);
  1033. d261 1
  1034. a261 1
  1035.              usprintf(ftp.control,noperm);
  1036. d263 1
  1037. a263 1
  1038.             usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  1039. d265 1
  1040. a265 1
  1041.             log(ftp.control,"RETR %s",file);
  1042. d267 1
  1043. a267 1
  1044.                 usprintf(ftp.control,binwarn,file);
  1045. d285 1
  1046. a285 1
  1047.              usprintf(ftp.control,noperm);
  1048. d287 1
  1049. a287 1
  1050.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  1051. d289 1
  1052. a289 1
  1053.             log(ftp.control,"STOR %s",file);
  1054. d296 1
  1055. a296 1
  1056.             usprintf(ftp.control,badport);
  1057. d298 1
  1058. a298 1
  1059.             usprintf(ftp.control,portok);
  1060. d305 1
  1061. a305 1
  1062.              usprintf(ftp.control,noperm);
  1063. d307 1
  1064. a307 1
  1065.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  1066. d316 1
  1067. a316 1
  1068.              usprintf(ftp.control,noperm);
  1069. d318 1
  1070. a318 1
  1071.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  1072. d327 1
  1073. a327 1
  1074.              usprintf(ftp.control,noperm);
  1075. d338 1
  1076. a338 1
  1077.             usprintf(ftp.control,pwdmsg,file);
  1078. d341 1
  1079. a341 1
  1080.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  1081. d347 1
  1082. a347 1
  1083.         usprintf(ftp.control,pwdmsg,ftp.cd);
  1084. d357 1
  1085. a357 1
  1086.         usprintf(ftp.control,unimp);
  1087. d362 1
  1088. a362 1
  1089.              usprintf(ftp.control,noperm);
  1090. d364 2
  1091. a365 2
  1092.             log(ftp.control,"DELE %s",file);
  1093.             usprintf(ftp.control,deleok);
  1094. d367 1
  1095. a367 1
  1096.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  1097. d373 1
  1098. a373 1
  1099.             usprintf(ftp.control,userfirst);
  1100. d382 1
  1101. a382 1
  1102.             usprintf(ftp.control,noperm);
  1103. d388 2
  1104. a389 2
  1105.             log(ftp.control,"MKD %s",file);
  1106.             usprintf(ftp.control,mkdok);
  1107. d391 1
  1108. a391 1
  1109.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  1110. d399 1
  1111. a399 1
  1112.              usprintf(ftp.control,noperm);
  1113. d401 2
  1114. a402 2
  1115.             log(ftp.control,"RMD %s",file);
  1116.             usprintf(ftp.control,deleok);
  1117. d404 1
  1118. a404 1
  1119.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  1120. d410 1
  1121. a410 1
  1122.             usprintf(ftp.control,unsupp);
  1123. d412 1
  1124. a412 1
  1125.             usprintf(ftp.control,okay);
  1126. d416 1
  1127. a416 1
  1128.             usprintf(ftp.control,unsupp);
  1129. d418 1
  1130. a418 1
  1131.             usprintf(ftp.control,okay);
  1132. d424 1
  1133. a424 1
  1134.     log(ftp.control,"close FTP");
  1135. d426 3
  1136. a428 3
  1137.     close_s(ftp.control);
  1138.     if(ftp.data != -1)
  1139.         close_s(ftp.data);
  1140. d487 1
  1141. a487 1
  1142.         usprintf(ftp->control,noperm);
  1143. d501 1
  1144. a501 1
  1145.     usprintf(ftp->control,logged);
  1146. d503 1
  1147. a503 1
  1148.         log(ftp->control,"%s logged in",ftp->username);
  1149. d505 1
  1150. a505 1
  1151.         log(ftp->control,"%s logged in, ID %s",ftp->username,pass);
  1152. d573 1
  1153. d575 1
  1154. a575 1
  1155.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  1156. d579 3
  1157. a581 3
  1158.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  1159.     usprintf(ftp->control,sending,command,file);
  1160.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  1161. d584 3
  1162. a586 3
  1163.         close_s(ftp->data);
  1164.         ftp->data = -1;
  1165.         usprintf(ftp->control,noconn);
  1166. d589 1
  1167. d595 3
  1168. a597 2
  1169.         usprintf(ftp->control,noconn);
  1170.         shutdown(ftp->data,2);    /* Blow away data connection */
  1171. d599 1
  1172. a599 1
  1173.         usprintf(ftp->control,txok);
  1174. d603 2
  1175. a604 2
  1176.     close_s(ftp->data);
  1177.     ftp->data = -1;
  1178. d618 1
  1179. d620 1
  1180. a620 1
  1181.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  1182. d624 3
  1183. a626 3
  1184.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  1185.     usprintf(ftp->control,sending,command,file);
  1186.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  1187. d629 3
  1188. a631 3
  1189.         close_s(ftp->data);
  1190.         ftp->data = -1;
  1191.         usprintf(ftp->control,noconn);
  1192. d634 1
  1193. d643 3
  1194. a645 2
  1195.         usprintf(ftp->control,writerr,sys_errlist[errno]);
  1196.         shutdown(ftp->data,2);    /* Blow it away */
  1197. d647 2
  1198. a648 2
  1199.         usprintf(ftp->control,rxok);
  1200.         close_s(ftp->data);
  1201. d650 1
  1202. a650 1
  1203.     ftp->data = -1;
  1204. @
  1205.  
  1206.  
  1207. 1.1
  1208. log
  1209. @Initial revision
  1210. @
  1211. text
  1212. @d13 1
  1213. d15 3
  1214. a19 3
  1215. #include "proc.h"
  1216. #include "dirutil.h"
  1217. #include "commands.h"
  1218. a465 82
  1219. /* Subroutine for logging in the user whose name is name and password is pass.
  1220.    The buffer path should be long enough to keep a line from the userfile.
  1221.    If pwdignore is true, the password check will be overridden.
  1222.    The return value is the permissions field or -1 if the login failed.
  1223.    Path is set to point at the path field, and pwdignore will be true if no
  1224.    particular password was needed for this user.
  1225.  */
  1226. int
  1227. userlogin(name,pass,path,len,pwdignore)
  1228. char *name;
  1229. char *pass;
  1230. char **path;
  1231. int len;            /* Length of buffer pointed at by *path */
  1232. int *pwdignore;
  1233. {
  1234.     char *cp,*cp1;
  1235.     FILE *fp;
  1236.     int anony,perm;
  1237.  
  1238.     if((fp = fopen(Userfile,READ_TEXT)) == NULLFILE)
  1239.         /* Userfile doesn't exist */
  1240.         return -1;
  1241.     while(fgets(*path,len,fp),!feof(fp)){
  1242.         if(*path[0] == '#')
  1243.             continue;    /* Comment */
  1244.         if((cp = strchr(*path,' ')) == NULLCHAR)
  1245.             /* Bogus entry */
  1246.             continue;
  1247.         *cp++ = '\0';        /* Now points to password */
  1248.         if(stricmp(name,*path) == 0)
  1249.             break;        /* Found user name */
  1250.     }
  1251.     if(feof(fp)){
  1252.         /* User name not found in file */
  1253.         fclose(fp);
  1254.         return -1;
  1255.     }
  1256.     fclose(fp);
  1257.     /* Look for space after password field in file */
  1258.     if((cp1 = strchr(cp,' ')) == NULLCHAR)
  1259.         /* Invalid file entry */
  1260.         return -1;
  1261.     *cp1++ = '\0';    /* Now points to path field */
  1262.     anony = *pwdignore;
  1263.     if(strcmp(cp,"*") == 0)
  1264.         anony = 1;    /* User ID is password-free */
  1265.     if(!anony && strcmp(cp,pass) != 0)
  1266.         /* Password required, but wrong one given */
  1267.         return -1;
  1268.     if((cp = strchr(cp1,' ')) == NULLCHAR)
  1269.         /* Permission field missing */
  1270.         return -1;
  1271.     *cp++ = '\0';    /* now points to permission field */
  1272.     perm = atoi(cp);
  1273. #if   defined(AMIGA)
  1274.     /*
  1275.      * Well, on the Amiga, a file can be referenced by many names:
  1276.      * device names (DF0:) or volume names (My_Disk:).  This hunk of code
  1277.      * passed the pathname specified in the ftpusers file, and gets the
  1278.      * absolute path copied into the user's buffer.  We really should just
  1279.      * allocate the buffer and return a pointer to it, since the caller
  1280.      * really doesn't have a good idea how long the path string is..
  1281.      */
  1282.     cp1 = pathname("", cp1);
  1283.     if (cp1)
  1284.         strcpy(*path, cp1);
  1285.     else
  1286.         **path = '\0';
  1287.     free(cp1);
  1288. #else
  1289.     strcpy(*path,cp1);
  1290.     /* Convert any backslashes to forward slashes, for backward
  1291.      * compatibility with the old NET
  1292.      */
  1293.     while((cp = strchr(*path,'\\')) != NULLCHAR)
  1294.         *cp = '/';
  1295. #endif
  1296.     *pwdignore = anony;
  1297.     /* Finally return the permission bits */
  1298.     return perm;
  1299. }
  1300.     
  1301. @
  1302.